﻿/********************************************************************************
** auth： Mine
** date： 2017/1/16 1:03:57
** desc： 对数据文件进行读写操作封装  加密序列化 http://blog.csdn.net/paiooo/article/details/7017211
** Ver.:  V1.0.0
*********************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;

namespace X_Code.io
{
    class MineDataIO
    {
        public Boolean WriteWithDefaultFile(Dictionary<String, Object> data)
        {
            //return SimpleWrite(GetDefaultFilePath(), data);
            return EncryptWrite(GetDefaultFilePath(), data);
        }
        /// <summary>
        /// 简单序列化map到指定路径文件,文件不存在将自动创建
        /// </summary>
        /// <param name="path"></param>
        /// <param name="data"></param>
        public Boolean SimpleWrite(String path,Dictionary<String, Object> data)
        {
            if (!CheckSome(path))
            {
                return false;
            }
            FileStream fs = null;
            try
            {
                fs = new FileStream(@path, FileMode.OpenOrCreate, FileAccess.Write);
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(fs, data);
            }
            catch(Exception e)
            {
                Console.WriteLine(e);
                return false;
            }
            finally
            {
                if(fs!=null)fs.Close();
            }
            return true;
        }
        /// <summary>
        /// 加密序列化写入
        /// </summary>
        /// <param name="path"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public Boolean EncryptWrite(String path, Dictionary<String, Object> data)
        {
            if (!CheckSome(path))
            {
                return false;
            }
            FileStream fs = null;
            MemoryStream ms = null;
            try
            {
                fs = new FileStream(@path, FileMode.OpenOrCreate, FileAccess.Write);
                ms = new MemoryStream();  //内存流
                BinaryFormatter bf = new BinaryFormatter();
                //序列化到内存流
                bf.Serialize(ms, data);
                //byte[] tempData = ms.ToArray();
                if (ms.Length > Int32.MaxValue)
                {
                    throw new Exception("数据过大！");
                }
                ms.Seek(0, SeekOrigin.Begin);
                byte[] tempData = ms.ToArray();

                
                //加密内存流
                byte[] encryptData = EncryptUtils.AES_CBC_Encrypt_Byte(
                                                    tempData,
                                                    MineInfo.ENCRYPT_AES_CBC_FILE_KEY,
                                                    MineInfo.ENCRYPT_AES_CBC_FILE_VI);
                //Console.WriteLine("Write:");
                //EncryptUtils.ShowBytes(tempData);
                //EncryptUtils.ShowBytes(encryptData);
                
                //将byte[]写入文件
                fs.Write(encryptData, 0, encryptData.Length);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return false;
            }
            finally
            {
                if (ms != null) ms.Close();
                if (fs != null) fs.Close();
            }
            return true;
        }

        //private void testWrite()
        //{
        //    //序列化测试-写
        //    List<Owner> list = new List<Owner>();
        //    Owner one = new Owner();
        //    one.Name = "1";
        //    Owner two = new Owner();
        //    two.Name = "2";
        //    list.Add(one);
        //    list.Add(two);
        //    Dictionary<String, Object> map = new Dictionary<String, Object>();
        //    map.Add("one", list);

        //    FileStream fs = new FileStream(@"D:\mine.data", FileMode.Create);
        //    BinaryFormatter bf = new BinaryFormatter();
        //    bf.Serialize(fs, map);
        //    fs.Close();
        //}
        public Dictionary<String, Object> ReadWithDefaultFile()
        {
           // return SimpleRead(GetDefaultFilePath());
            return EncryptRead(GetDefaultFilePath());
            
        }
        /// <summary>
        /// 从指定路径读取序列化data
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public Dictionary<String, Object> SimpleRead(String path)
        {
            if (!File.Exists(@path))
            {
                return null;
            }
            FileStream fs = null;
            try
            {
                fs = new FileStream(@path, FileMode.Open, FileAccess.Read);
                BinaryFormatter bf = new BinaryFormatter();
                Dictionary<String, Object> data = bf.Deserialize(fs) as Dictionary<String, Object>;
                return data;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return null;
            }
            finally
            {
                if (fs != null) fs.Close();
            }
        }
        /// <summary>
        /// 加密序列化读出
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public Dictionary<String, Object> EncryptRead(String path)
        {
            if (!File.Exists(@path))
            {
                return null;
            }
            FileStream fs = null;
            MemoryStream ms = null;
            try
            {
                fs = new FileStream(@path, FileMode.Open, FileAccess.Read);
                ms = new MemoryStream();  //内存流
                BinaryFormatter bf = new BinaryFormatter();
                //将流读取到byte[]数组
                if (fs.Length>Int32.MaxValue)
                {
                    throw new Exception("数据过大！");  
                }
                byte[] encryptData =new byte[fs.Length];
                
                fs.Read(encryptData, 0, (int)fs.Length);

                //解密byte数组并写入内存流
                byte[] tempData = EncryptUtils.AES_CBC_Decrypt_Byte(
                                                    encryptData,
                                                    MineInfo.ENCRYPT_AES_CBC_FILE_KEY,
                                                    MineInfo.ENCRYPT_AES_CBC_FILE_VI);
                ms.Seek(0, SeekOrigin.Begin);
                ms.Write(tempData, 0, tempData.Length);
                ms.Flush();
                
                //Console.WriteLine("Read:");
                //EncryptUtils.ShowBytes(tempData);
                //EncryptUtils.ShowBytes(encryptData);
                //Console.WriteLine();

                //之前用过ms,所以要把指针还原，否则反序列化会抛异常
                ms.Seek(0, SeekOrigin.Begin);
                //反序列化
                Dictionary<String, Object> data = bf.Deserialize(ms) as Dictionary<String, Object>;
                return data;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return null;
            }
            finally
            {
                if (ms != null) ms.Close();
                if (fs != null) fs.Close();
            }
        }

        //private void testRead()
        //{
        //    //序列化测试-读
        //    FileStream fs = new FileStream(@"D:\mine.data", FileMode.Open);
        //    BinaryFormatter bf = new BinaryFormatter();
        //    Dictionary<String, Object> map = bf.Deserialize(fs) as Dictionary<String, Object>;
        //    List<Owner> list = map["one"] as List<Owner>;
        //    foreach (Owner one in list)
        //    {
        //        Console.WriteLine(one);
        //    }
        //}
        //检验文件路径是否合法,有必要吗。。。
        public static String GetDefaultFilePath() { 
           //获取当前exe程序目录路径
            string path = Environment.CurrentDirectory;
            //获取数据文件默认名
            string name = MineInfo.DEFAULT_FILE;
            //拼接返回
            return path+@"\"+name;
        }

        public static FileInfo GetDefaultFileInfo()
        {
            return new FileInfo(GetDefaultFilePath());
        }
        private Boolean CheckSome(String path)
        {
            if (Path.GetFileName(path) == null)
            {
                return false;
            }
            if (Path.GetDirectoryName(path) == null)
            {
                return false;
            }
            return true;
        }


    }
}
